﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;


namespace GraphicsEditor
{
    public partial class ScrollableCanvasForm : Form
    {
        private const string CLP_FORMAT = "GRAPHIC_EDITOR_DATA";
        Shape rubber = null;
        Shape selectedShape = null;
        private List<Shape> shapeList = new List<Shape>();
        private Point moveOrigin;



        private static string NOFILENAME_TEXT = "Untitled";

        //private Bitmap canvas;
        //public Bitmap Canvas
        //{
        //    get
        //    {
        //        return canvas;
        //    }
        //    set
        //    {
        //        canvas = new Bitmap(value.Size.Width, value.Size.Height);

        //        Graphics graphics = Graphics.FromImage(canvas);
        //        graphics.DrawImage(value, 0, 0);
        //        graphics.Dispose();

        //        AutoScrollMinSize = canvas.Size;
        //    }
        //}

        private string fileName;
        public string FileName
        {
            get
            {
                return fileName;
            }
            set
            {
                fileName = value;

                if (value.Equals(""))
                {
                    Text = NOFILENAME_TEXT;
                }
                else
                {
                    FileInfo fileInfo = new FileInfo(value);
                    Text = fileInfo.Name;
                }
            }
        }

        public GraphicsEditor.DrawMode drawMode = GraphicsEditor.DrawMode.Rectangle;

        public GraphicsEditor.DrawMode Mode
        {
            get
            {
                return drawMode;
            }
            set
            {
                drawMode = value;
                if (drawMode != GraphicsEditor.DrawMode.Select && selectedShape != null)
                {
                    selectedShape = null;
                    Refresh();
                }
            }
        }

        private ShapePen pen = new ShapePen();
        public ShapePen Pen
        {
            get
            {
                return pen;
            }
            set
            {
                pen = value;
            }
        }

        private ShapeBrush brush = new ShapeBrush();
        public ShapeBrush Brush
        {
            get
            {
                return brush;
            }
            set
            {
                brush = value;
            }
        }


        public delegate void DrawingToolRequestHandler();
        //public event DrawingToolRequestHandler DrawingToolRequested;

        public ScrollableCanvasForm(string fileName, Size size)
        {
            InitializeComponent();
            FileName = fileName;
            AutoScrollMinSize = size;
        }

        ///*
        // * Reference: http://www.bobpowell.net/understanding_autoscroll.htm
        // */
        //private void ScrollableCanvasForm_Paint(object sender, PaintEventArgs e)
        //{
        //    Graphics graphics = e.Graphics;

        //    Matrix mx = new Matrix(1, 0, 0, 1, AutoScrollPosition.X, AutoScrollPosition.Y);
        //    graphics.Transform = mx;
        //    graphics.DrawImage(Canvas, new Point(0, 0));

        //    graphics.Dispose();
        //}

        /// <summary>
        /// Save to a file
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool Save(string filename)
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = null;
            try
            {
                stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
                ShapeFile sf = new ShapeFile();
                sf.ShapeList = shapeList;
                sf.Size = AutoScrollMinSize;
                formatter.Serialize(stream, sf);
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }
            return true;
        }

        /// <summary>
        /// Open from a file
        /// </summary>
        /// <param name="filename"></param>
        public void Open(string filename)
        {
            Stream stream = null;
            IFormatter formatter = new BinaryFormatter();
            try
            {
                stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                ShapeFile sf = (ShapeFile)formatter.Deserialize(stream);
                shapeList = sf.ShapeList;
                AutoScrollMinSize = sf.Size;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }

        }
        private void paintWindow(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            //Matrix mx = new Matrix(1, 0, 0, 1, AutoScrollPosition.X, AutoScrollPosition.Y);
            //g.Transform = mx;
            //g.DrawImage(Canvas, new Point(0, 0));



            foreach (Shape s in shapeList)
            {
                s.Draw(g);
            }

            if (selectedShape != null)
            {
                Rectangle r = selectedShape.GetBoundingRect();
                r.Inflate(2, 2);
                g.DrawRectangle(new Pen(Color.Red), r);
            }
            g.Dispose();

        }

        private void Child_MouseDown(object sender, MouseEventArgs e)
        {
            //DrawingToolRequested();

            Point p = new Point(e.X, e.Y);
            switch (drawMode)
            {

                case GraphicsEditor.DrawMode.Line:
                    if (rubber == null)
                    {
                        rubber = new Line(pen, brush);
                        rubber.AddPoint(p);
                    }
                    break;
                case GraphicsEditor.DrawMode.Rectangle:
                    if (rubber == null)
                    {
                        rubber = new Rect(pen, brush);
                        rubber.AddPoint(p);
                    }
                    break;

                case GraphicsEditor.DrawMode.Ellipse:
                    if (rubber == null)
                    {
                        rubber = new Ellipse(pen, brush);
                        rubber.AddPoint(p);
                    }
                    break;
                case GraphicsEditor.DrawMode.Polygon:
                    if (rubber == null)
                    {
                        rubber = new Polygon(pen, brush);
                        rubber.AddPoint(p);
                    }
                    else if (rubber.IsEnd(p))
                    {
                        rubber.RemoveAt(rubber.NumOfPoints - 1);
                        shapeList.Add(rubber);
                        rubber = null;
                        Invalidate();

                    }
                    else
                    {
                        rubber.AddPoint(p);
                    }
                    break;

                case GraphicsEditor.DrawMode.Select:
                    selectedShape = null;
                    for (int i = shapeList.Count - 1; i >= 0; i--)
                    {
                        Shape s = shapeList[i];
                        if (s.PtInShape(new Point(e.X, e.Y)))
                        {
                            selectedShape = s;
                            break;
                        }
                    }

                    Invalidate();
                    if (selectedShape != null)
                    {
                        moveOrigin.X = e.X;
                        moveOrigin.Y = e.Y;
                    }
                    break;
            }
        }

        private void Child_MouseMove(object sender, MouseEventArgs e)
        {
            if (drawMode != GraphicsEditor.DrawMode.Select)
            {
                if (rubber != null)
                {
                    Rectangle r = rubber.GetBoundingRect();
                    r.Inflate(rubber.Pen.Width + 1, rubber.Pen.Width + 1);
                    Invalidate(r);
                    Update();
                    if (rubber.NumOfPoints == 1)
                    {
                        rubber.AddPoint(new Point(e.X, e.Y));
                    }

                    if (drawMode == GraphicsEditor.DrawMode.Polygon)
                    {
                        rubber[rubber.NumOfPoints - 1] = new Point(e.X, e.Y);
                    }
                    else if (e.Button == MouseButtons.Left)
                    {
                        rubber[1] = new Point(e.X, e.Y);
                    }

                    Graphics g = CreateGraphics();
                    rubber.Draw(g);
                    g.Dispose();
                }
            }
            else if (e.Button == MouseButtons.Left && selectedShape != null)
            {
                selectedShape.Offset(e.X - moveOrigin.X, e.Y - moveOrigin.Y);
                moveOrigin.X = e.X;
                moveOrigin.Y = e.Y;
                Refresh();
            }



        }



        public void CopyShape()
        {


            if (selectedShape != null)
            {


                DataFormats.Format format = DataFormats.GetFormat(CLP_FORMAT);
                IDataObject ido = new DataObject();
                ido.SetData(format.Name, false, selectedShape);
                Clipboard.SetDataObject(ido, true);
            }

        }

        public void PasteShape()
        {
            IDataObject ido2 = Clipboard.GetDataObject();
            if (ido2.GetDataPresent(CLP_FORMAT))
            {
                Shape s = ido2.GetData(CLP_FORMAT) as Shape;
                s.Offset(10, 10);
                shapeList.Add(s);
                Invalidate();
            }
        }



        private void Child_MouseUp(object sender, MouseEventArgs e)
        {

            if (drawMode != GraphicsEditor.DrawMode.Polygon && rubber != null)
            {
                shapeList.Add(rubber);
                rubber = null;
                Invalidate();
            }
        }


    }

}


